package xj.graph2d.app.prop;

import java.awt.Color;
import java.util.Comparator;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import xj.graph2d.app.resources.Style;
import xj.graph2d.table.FeatureTable;
import xj.graph2d.table.FeatureTableEntry;
import xj.model.uml.Attribute;
import xj.model.uml.BasicModelElement;
import xj.model.uml.Changeability;
import xj.model.uml.CollectionType;
import xj.model.uml.Multiplicity;
import xj.model.uml.Visibility;

public class UMLAttributeEntry implements FeatureTableEntry {

  // position of each column
  public static final int NAME_COLUMN = 0;

  public static final int TYPE_COLUMN = 1;

  public static final int INIT_VALUE_COLUMN = 2;

  public static final int VISIBILITY_COLUMN = 3;

  public static final int CHANGEABILITY_COLUMN = 4;

  public static final int MULTIPLICITY_COLUMN = 5;

  public static final int COLLECTION_COLUMN = 6;

  public static final int STATIC_COLUMN = 7;

  public static final int DELETE_COLUMN = 8;

  public static final String[] columnNames = { 
    "Name", 
    "Type", 
    "Init vaule",
    "Visibility", 
    "Changeability", 
    "Multiplicity", 
    "Collection", 
    "Static",
    "Delete",
  };

  public static final String[] columnTips = { 
    "Name of the attribute",
    "Type of the attribute", 
    "Initial value of the attribute (optional)",
    "Visibility of the attribute", 
    "Changeability of the attribute",
    "Multiplicity of the attribute", 
    "Collection type of the attribute",
    "Is the attribute static?", 
    "Delete the marked attribute",
  };

  public static final Comparator[] comparators = {
      new FeatureEntryComparator(NAME_COLUMN),
      new FeatureEntryComparator(TYPE_COLUMN),
      new FeatureEntryComparator(INIT_VALUE_COLUMN),
      new FeatureEntryComparator(VISIBILITY_COLUMN),
      new FeatureEntryComparator(CHANGEABILITY_COLUMN),
      new FeatureEntryComparator(MULTIPLICITY_COLUMN),
      new FeatureEntryComparator(COLLECTION_COLUMN),
      new FeatureEntryComparator(STATIC_COLUMN), null, };

  public static TableCellEditor[] editors = new TableCellEditor[9];

  static {
    JComboBox type = new JComboBox();
    type.addItem("");
    type.addItem("boolean");
    type.addItem("int");
    type.addItem("char");
    type.addItem("byte");
    type.addItem("long");
    type.addItem("short");
    type.addItem("double");
    type.addItem("float");
    type.addItem("Collection");
    type.addItem("List");
    type.addItem("Set");
    type.addItem("Map");
    type.addItem("Object");
    type.addItem("String");
    type.addItem("Date");
    type.addItem("Time");
    type.setEditable(true);
    type.setBackground(Color.white);
    type.setFont(Style.editorFont);
    editors[TYPE_COLUMN] = new DefaultCellEditor(type);

    JComboBox init = new JComboBox();
    init.addItem("");
    init.addItem("0");
    init.addItem("null");
    init.addItem("\"\"");
    init.addItem("false");
    init.addItem("true");
    init.setEditable(true);
    init.setBackground(Color.white);
    init.setFont(Style.editorFont);
    editors[INIT_VALUE_COLUMN] = new DefaultCellEditor(init);

    JComboBox visibility = new JComboBox();
    visibility.addItem("");
    visibility.addItem("public");
    visibility.addItem("protected");
    visibility.addItem("private");
    visibility.addItem("package");
    visibility.setBackground(Color.white);
    visibility.setFont(Style.editorFont);
    editors[VISIBILITY_COLUMN] = new DefaultCellEditor(visibility);

    JComboBox changeability = new JComboBox();
    changeability.addItem(Changeability.Changeable);
    changeability.addItem(Changeability.Constant);
    changeability.addItem(Changeability.Derived);
    changeability.addItem(Changeability.AddOnly);
    changeability.setBackground(Color.white);
    changeability.setFont(Style.editorFont);
    editors[CHANGEABILITY_COLUMN] = new DefaultCellEditor(changeability);

    JComboBox multiplicity = new JComboBox();
    multiplicity.addItem("");
    multiplicity.addItem(Multiplicity.toString(Multiplicity.One));
    multiplicity.addItem(Multiplicity.toString(Multiplicity.ZeroOrOne));
    multiplicity.addItem(Multiplicity.toString(Multiplicity.OneToMany));
    multiplicity.addItem(Multiplicity.toString(Multiplicity.Many));
    multiplicity.setEditable(true);
    multiplicity.setBackground(Color.white);
    multiplicity.setFont(Style.editorFont);
    editors[MULTIPLICITY_COLUMN] = new DefaultCellEditor(multiplicity);

    JComboBox collection = new JComboBox();
    collection.addItem("");
    collection.addItem(CollectionType.toString(CollectionType.Set));
    collection.addItem(CollectionType.toString(CollectionType.Bag));
    collection.addItem(CollectionType.toString(CollectionType.List));
    collection.addItem(CollectionType.toString(CollectionType.OrderedSet));
    collection.setBackground(Color.white);
    collection.setFont(Style.editorFont);
    editors[COLLECTION_COLUMN] = new DefaultCellEditor(collection);
  }

  public static TableCellRenderer[] renderers = { 
    null, null, null, null, null, null, null, null, 
    new FeatureTable.GrayBooleanRenderer(), // for Delete
  };

  public static final int[] columnWidths = { 50, 50, 50, 50, 50, 50, 50, 20, 20, };

  public UMLAttributeEntry(Attribute attribute) {
    this.attribute = attribute;
  }

  public int getColumnCount() {
    return columnNames.length;
  }

  public String getColumnName(int col) {
    if (col >= 0 && col < columnNames.length) {
      return columnNames[col];
    }
    return null;
  }

  public Object getColumnValue(int col) {
    if (attribute != null && col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	return attribute.getName();
      case TYPE_COLUMN:
	return attribute.getType();
      case INIT_VALUE_COLUMN:
	return attribute.getInitValue();
      case VISIBILITY_COLUMN:
	return attribute.getVisibility().toDisplayString();
      case CHANGEABILITY_COLUMN:
	return attribute.getChangeability();
      case MULTIPLICITY_COLUMN:
	return Multiplicity.toString(attribute.getMultiplicity());
      case COLLECTION_COLUMN:
	return CollectionType.toString(attribute.getCollectionType());
      case STATIC_COLUMN:
	return attribute.isStatic();
      case DELETE_COLUMN:
	return deleted;
      }
    }
    return null;
  }

  public void setColumnValue(int col, Object value) {
    if (attribute != null && col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	if (value != null) {
	  attribute.setName(value.toString());
	} else {
	  attribute.setName(null);
	}
	break;
      case TYPE_COLUMN:
	if (value != null) {
	  attribute.setType(value.toString());
	} else {
	  attribute.setType(null);
	}
	break;
      case INIT_VALUE_COLUMN:
	if (value != null) {
	  attribute.setInitValue(value.toString());
	} else {
	  attribute.setInitValue(null);
	}
	break;
      case VISIBILITY_COLUMN:
	if (value instanceof Visibility) {
	  attribute.setVisibility((Visibility) value);
	} else if (value instanceof String) {
	  attribute.setVisibility(Visibility.toVisibility((String) value));
	}
	break;
      case CHANGEABILITY_COLUMN:
	if (value instanceof Changeability) {
	  attribute.setChangeability((Changeability) value);
	}
	break;
      case MULTIPLICITY_COLUMN:
	if (value instanceof String) {
	  attribute.setMultiplicity(Multiplicity.toMultiplicity((String) value));
	}
	break;
      case COLLECTION_COLUMN:
	if (value instanceof String) {
	  attribute.setCollectionType(CollectionType.toCollectionType((String) value));
	}
	break;
      case STATIC_COLUMN:
	if (value instanceof Boolean) {
	  attribute.setStatic(((Boolean) value).booleanValue());
	}
	break;
      case DELETE_COLUMN:
	if (value instanceof Boolean) {
	  deleted = ((Boolean) value).booleanValue();
	}
	break;
      }
    }
  }

  public String getColumnTip(int col) {
    if (col >= 0 && col < columnTips.length) {
      return columnTips[col];
    }
    return null;
  }

  public Class getColumnClass(int col) {
    switch (col) {
    case NAME_COLUMN:
      return String.class;
    case TYPE_COLUMN:
      return String.class;
    case INIT_VALUE_COLUMN:
      return Object.class;
    case VISIBILITY_COLUMN:
      return String.class;
    case CHANGEABILITY_COLUMN:
      return Changeability.class;
    case MULTIPLICITY_COLUMN:
      return String.class;
    case COLLECTION_COLUMN:
      return String.class;
    case STATIC_COLUMN:
      return Boolean.class;
    case DELETE_COLUMN:
      return Boolean.class;
    default:
      return String.class;
    }
  }

  public Comparator getColumnComparator(int col) {
    if (col >= 0 && col < comparators.length) {
      return comparators[col];
    }
    return null;
  }

  public TableCellEditor getColumnEditor(int col) {
    if (col >= 0 && col < editors.length) {
      return editors[col];
    }
    return null;
  }

  public boolean isColumnEditable(int col) {
    if (col >= 0 && col < columnNames.length) {
      return true;
      // return (col != DELETE_COLUMN);
    }
    return false;
  }

  public TableCellRenderer getColumnRenderer(int col) {
    if (col >= 0 && col < renderers.length) {
      return renderers[col];
    }
    return null;
  }

  public int getColumnWidth(int col) {
    if (col >= 0 && col < columnWidths.length) {
      return columnWidths[col];
    }
    return -1;
  }

  public Attribute getAttribute() {
    return attribute;
  }

  public String getName() {
    if (attribute != null) {
      return attribute.getName();
    }
    return null;
  }

  public BasicModelElement getModelElement() {
    return attribute;
  }

  public boolean isDeleted() {
    return deleted;
  }

  public boolean isEditable() {
    return true;
  }

  protected Attribute attribute;

  protected boolean deleted;

  static public class FeatureEntryComparator implements Comparator {

    public FeatureEntryComparator(int col) {
      this.col = col;
    }

    public int compare(Object o1, Object o2) {
      if (o1 instanceof UMLAttributeEntry && o2 instanceof UMLAttributeEntry) {
	UMLAttributeEntry e1 = (UMLAttributeEntry) o1;
	UMLAttributeEntry e2 = (UMLAttributeEntry) o2;
	Object v1 = e1.getColumnValue(col);
	Object v2 = e2.getColumnValue(col);
	if (v1 != null && v2 != null) {
	  switch (col) {
	  case INIT_VALUE_COLUMN:
	  case MULTIPLICITY_COLUMN:
	  case COLLECTION_COLUMN:
	    return (v1.toString()).compareTo(v2.toString());
	  case VISIBILITY_COLUMN:
	    return ((Visibility) v1).compareTo((Visibility) v2);
	  case CHANGEABILITY_COLUMN:
	    return ((Changeability) v1).compareTo((Changeability) v2);
	  case STATIC_COLUMN:
	    return ((Boolean) v1).compareTo((Boolean) v2);
	  default:
	    return ((String) v1).compareTo((String) v2);
	  }
	}
      }
      return 0;
    }

    protected int col;
  }

}
